package com.example.sturedis.controller;

import com.alibaba.fastjson.JSON;
import com.example.sturedis.consts.StuRedisConst;
import com.example.sturedis.pojo.Student;
import com.example.sturedis.service.StudentService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/stu")
@Slf4j
public class StudentController4 implements InitializingBean {

    @Autowired
    private RedissonClient redissonClient;

    private RBloomFilter<Integer> stuBloom;


    @Override
    public void afterPropertiesSet() throws Exception {
        //① 对布隆过滤器进行初始化
        stuBloom = redissonClient.getBloomFilter("stuBloom");
        /*
            参数一：期望向布隆过滤器中添加的值的个数
            参数二：误判的概率
         */
        stuBloom.tryInit(1000,0.01);

        //② 向布隆过滤器中存入数据库中存在的id值
        List<Integer> ids = studentService.getIds();
//        ids.forEach(id->stuBloom.add(id));
        ids.forEach(stuBloom::add);
    }

    @Autowired
    private StudentService studentService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @GetMapping("/{id}")
    public Student findById(@PathVariable("id")Integer id){

        String key = StuRedisConst.STU_CACHE_PREFIX + id; //CACHE:STU:ID:2

        //③ 判断布隆过滤器中是否存在这个id
        if (!stuBloom.contains(id)){
            log.info("数据库不存在id为{}的记录",id);
            return null;
        }

        //先查询缓存
        String value = redisTemplate.opsForValue().get(key);
        if (StringUtils.isEmpty(value)){
            //缓存没查到--查询数据库 + 存入缓存 + 返回数据
            Student stu = null;
            //加锁，解决缓存击穿问题
            String lockName = StuRedisConst.STU_LOCK_PREFIX+id;
            RLock lock = redissonClient.getLock(lockName);

            try {
                //加锁
                lock.lock();

                //进行二次判断缓存是否存在
                value = redisTemplate.opsForValue().get(key);
                if (StringUtils.isEmpty(value)) {
                    log.info("缓存中没有数据，当前从数据库查询的id为：{}", id);
                    stu = studentService.getById(id);
                    if (stu != null) {
                        //存入缓存
                        redisTemplate.opsForValue().set(key, JSON.toJSONString(stu),5, TimeUnit.SECONDS);
                    }
                }else{
                    log.info("命中缓存,当前查询的id为：{}",id);
                    stu = JSON.parseObject(value,Student.class);
                }
            }finally {
                //释放做
                lock.unlock();
            }

            return stu;
        }

        log.info("命中缓存,当前查询的id为：{}",id);
        //缓存中有，返回数据
        Student stu = JSON.parseObject(value, Student.class);
        return stu;
    }

}
